package utils

import (
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"github.com/spf13/cast"
	"gopkg.in/yaml.v3"
	"io/ioutil"
	"math"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

func Base64Encode(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))

}

func Base64Decode(s string) string {
	decoded, _ := base64.StdEncoding.DecodeString(s)
	return string(decoded)
}

func InStringArray(s string, arr []string) bool {
	for _, s1 := range arr {
		if s == s1 {
			return true
		}
	}
	return false
}

func NewMd5Password(password string, secret string) string {
	return Md5Sum(secret + Md5Sum(password) + secret)
}

func Md5Sum(s string) string {
	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
}

func FmtPageParams(pageNum, pageSize int64) (int64, int64) {
	if pageSize <= 0 || pageSize > 1000 {
		pageSize = 1000
	}
	if pageNum <= 0 {
		pageNum = 1
	}

	return pageNum, pageSize
}

// CompareVersion 比较版本,-1:小于,0:相等,1:大于
// v1.1.1 compare v1.2.1
func CompareVersion(ver, cVer string) int {
	if strings.HasPrefix(ver, "v") {
		ver = ver[1:]
	}
	if strings.HasPrefix(cVer, "v") {
		cVer = cVer[1:]
	}
	verArr := strings.Split(ver, ".")   //当前的版本
	cVerArr := strings.Split(cVer, ".") //比较的版本

	var max int
	if len(verArr) >= len(cVerArr) {
		max = len(verArr)
	} else {
		max = len(cVerArr)
	}

	for i := 0; i < max; i++ {
		cv := 0
		v := 0
		if i >= len(verArr) {
			v = 0
		} else {
			v, _ = strconv.Atoi(verArr[i])
		}

		if i >= len(cVerArr) {
			cv = 0
		} else {
			cv, _ = strconv.Atoi(cVerArr[i])
		}
		if v < cv {
			return -1
		}
		if v > cv {
			return 1
		}
	}
	return 0
}

func ReadYaml(data interface{}, yamlContent string) error {
	err := yaml.Unmarshal([]byte(yamlContent), data)
	if err != nil {
		return err
	}
	return nil
}

func ReadYamlFile(data interface{}, configPath string) error {
	yamlFile, err := ioutil.ReadFile(configPath)
	if err != nil {
		return err
	}
	err = yaml.Unmarshal(yamlFile, data)
	if err != nil {
		return err
	}
	return nil
}

// Interface2Int64 任意值转int64
func Interface2Int64(d interface{}) int64 {
	return cast.ToInt64(d)
}

// Interface2Float64 任意值转float64
func Interface2Float64(d interface{}) float64 {
	return cast.ToFloat64(d)
}

// StringToBytes converts string to byte slice without a memory allocation.
func StringToBytes(s string) []byte {
	return *(*[]byte)(unsafe.Pointer(
		&struct {
			string
			Cap int
		}{s, len(s)},
	))
}

// BytesToString converts byte slice to string without a memory allocation.
func BytesToString(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// SliceInt64ToMap 切片转map（去重）
func SliceInt64ToMap(src []int64) map[int64]bool {
	m := make(map[int64]bool)
	for _, v := range src {
		if _, exist := m[v]; exist {
			continue
		}
		m[v] = true
	}
	return m
}

// LoopDo 重复执行
func LoopDo(f func() bool, dur time.Duration) func() {
	return func() {
		for {
			if !f() {
				return
			}
			time.Sleep(dur)
		}
	}
}

// LoopDoI 重复执行(执行包含序号i)
func LoopDoI(f func(int64) bool, dur time.Duration) func() {
	var i int64 = 0
	return func() {
		for {
			if !f(i) {
				return
			}
			i++
			time.Sleep(dur)
		}
	}
}

func MaxInt(a int, b int) int {
	return int(math.Max(float64(a), float64(b)))
}

func MinInt(a int, b int) int {
	return int(math.Min(float64(a), float64(b)))
}

func MaxInt64(a int64, b int64) int64 {
	return int64(math.Max(float64(a), float64(b)))
}

func MinInt64(a int64, b int64) int64 {
	return int64(math.Min(float64(a), float64(b)))
}

// IsNil 判断是否是nil
func IsNil(t interface{}) bool {
	if t == nil {
		return true
	}
	if fmt.Sprint(t) == "<nil>" {
		return true
	}
	return false
}

// MoreValueChooseInt64 多个值选择int64，若没有more则默认value，有more则选择more的第一个
func MoreValueChooseInt64(value int64, more ...int64) int64 {
	if len(more) > 0 {
		return more[0]
	}
	return value
}

// MoreValueChooseString 多个值选择string，若没有more则默认value，有more则选择more的第一个
func MoreValueChooseString(value string, more ...string) string {
	if len(more) > 0 {
		return more[0]
	}
	return value
}

// MoreValueChooseFloat64 多个值选择string，若没有more则默认value，有more则选择more的第一个
func MoreValueChooseFloat64(value float64, more ...float64) float64 {
	if len(more) > 0 {
		return more[0]
	}
	return value
}
